/*
 * Copyright (c) 2022 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

/**
 * @file
 *   This file implements the handler for data model messages.
 */

#include "window_covering.h"
#include <app_config.h>

#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/callback.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/CommandHandler.h>
#include <app/ConcreteAttributePath.h>
#include <app/ConcreteCommandPath.h>
#include <app/clusters/window-covering-server/window-covering-server.h>
#include <app/util/af.h>

using namespace ::chip;
using namespace ::chip::app::Clusters::WindowCovering;

void MatterPostAttributeChangeCallback(const app::ConcreteAttributePath &attributePath, uint8_t type, uint16_t size,
				       uint8_t *value)
{
	switch (attributePath.mClusterId) {
	case app::Clusters::Identify::Id:
		ChipLogProgress(Zcl, "Identify cluster ID: " ChipLogFormatMEI " Type: %u Value: %u, length: %u",
				ChipLogValueMEI(attributePath.mAttributeId), type, *value, size);
		break;
	case app::Clusters::WindowCovering::Id:
		ChipLogProgress(Zcl, "Window covering cluster ID: " ChipLogFormatMEI " Type: %u Value: %u, length: %u",
				ChipLogValueMEI(attributePath.mAttributeId), type, *value, size);
		break;
	default:
		break;
	}
}

/* Forwards all attributes changes */
void MatterWindowCoveringClusterServerAttributeChangedCallback(const app::ConcreteAttributePath &attributePath)
{
	if (attributePath.mEndpointId == WindowCovering::Endpoint()) {
		switch (attributePath.mAttributeId) {
		case Attributes::TargetPositionLiftPercent100ths::Id:
			WindowCovering::Instance().StartMove(WindowCovering::MoveType::LIFT);
			break;
		case Attributes::TargetPositionTiltPercent100ths::Id:
			WindowCovering::Instance().StartMove(WindowCovering::MoveType::TILT);
			break;
		case Attributes::CurrentPositionLiftPercent100ths::Id:
			WindowCovering::Instance().PositionLEDUpdate(WindowCovering::MoveType::LIFT);
			break;
		case Attributes::CurrentPositionTiltPercent100ths::Id:
			WindowCovering::Instance().PositionLEDUpdate(WindowCovering::MoveType::TILT);
			break;
		default:
			WindowCovering::Instance().SchedulePostAttributeChange(attributePath.mEndpointId,
									       attributePath.mAttributeId);
			break;
		};
	}
}

void emberAfWindowCoveringClusterInitCallback(chip::EndpointId endpoint)
{
	const auto logOnFailure = [](EmberAfStatus status, const char *attributeName) {
		if (status != EMBER_ZCL_STATUS_SUCCESS) {
			ChipLogError(Zcl, "Failed to set WindowCovering %s: %x", attributeName, status);
		}
	};

	app::DataModel::Nullable<chip::Percent100ths> currentPercent100ths;
	app::DataModel::Nullable<chip::Percent100ths> targetPercent100ths;
	app::DataModel::Nullable<chip::Percent> currentPercentage;
	EmberAfStatus status;

	status = Attributes::CurrentPositionLiftPercentage::Get(endpoint, currentPercentage);
	if (currentPercentage.IsNull()) {
		logOnFailure(Attributes::CurrentPositionLiftPercentage::Set(endpoint, 0),
			     "current position lift percentage");
	}

	status = Attributes::CurrentPositionTiltPercentage::Get(endpoint, currentPercentage);
	if (currentPercentage.IsNull()) {
		logOnFailure(Attributes::CurrentPositionTiltPercentage::Set(endpoint, 0),
			     "current position tilt percentage");
	}

	status = Attributes::CurrentPositionLiftPercent100ths::Get(endpoint, currentPercent100ths);
	if (currentPercent100ths.IsNull()) {
		currentPercent100ths.SetNonNull(0);
		logOnFailure(Attributes::CurrentPositionLiftPercent100ths::Set(endpoint, 0),
			     "current position lift percent 100ths");
	}

	status = Attributes::TargetPositionLiftPercent100ths::Get(endpoint, targetPercent100ths);
	if (targetPercent100ths.IsNull()) {
		logOnFailure(Attributes::TargetPositionLiftPercent100ths::Set(endpoint, currentPercent100ths),
			     "target position lift percent 100ths");
	}

	status = Attributes::CurrentPositionTiltPercent100ths::Get(endpoint, currentPercent100ths);
	if (currentPercent100ths.IsNull()) {
		currentPercent100ths.SetNonNull(0);
		logOnFailure(Attributes::CurrentPositionTiltPercent100ths::Set(endpoint, 0),
			     "current position tilt percent 100ths");
	}

	status = Attributes::TargetPositionTiltPercent100ths::Get(endpoint, targetPercent100ths);
	if (targetPercent100ths.IsNull()) {
		logOnFailure(Attributes::TargetPositionTiltPercent100ths::Set(endpoint, currentPercent100ths),
			     "target position tilt percent 100ths");
	}
}
